
/**
\file
Definition of the nmn::logger class.
\author Sean Tromans
*/

#ifndef	NMN_TEMPLATE_LOGGER_HPP
#define	NMN_TEMPLATE_LOGGER_HPP

#include <needs_more_ninja/template/create_string.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/noncopyable.hpp>

#if	defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4512)
#endif

#include <boost/signals2.hpp>

#if	defined(BOOST_MSVC)
#pragma warning(pop)
#endif

#include <exception>

namespace nmn
{

	/**
	Simple, thread safe logging class.
	\note
		Achieves thread safety via a simple mutex. This ensures your handler will not be called before the previous log has finished, no other thread safety guarantees are made.
	\author Sean Tromans
	*/
	template< typename char_t, typename traits_t = std::char_traits< char_t >, typename allocator_t = std::allocator< char_t > >
	class logger : private boost::noncopyable
	{
		//
		//	Public Member Types
		//
		public:

			typedef typename char_t	char_type;
			typedef typename std::basic_string< char_t, traits_t, allocator_t > string_type;

			typedef typename boost::signals2::signal< void ( typename string_type const & message, typename string_type const & formatted_message ) > handler_signal_type;
			typedef	boost::signals2::connection	signal_connection_type;

		//
		//	Public Member Functions
		//
		public:

			/**
			Register a log handler with the logger.
			@param The new log handler to process log output.
			@return A connection to the internal signal.
			\author Sean Tromans
			*/
			signal_connection_type register_handler( typename handler_signal_type::slot_type const & handler );

			/**
			Outputs a string to the log handlers.
			@param message The message to output to the log.
			\note
				Does not return until all handlers have finished processing.
				Should not be called recursively.
			\author Sean Tromans
			*/
			void operator( )( typename char_type const * const message );

			/**
			Outputs a string to the log handlers.
			@param message The message to output to the log.
			\note
				Does not return until all handlers have finished processing.
				Should not be called recursively.
			\author Sean Tromans
			*/
			void operator( )( typename string_type const & message );

		//
		//	Private Member Variables
		//
		private:

			boost::mutex		mutex;
			handler_signal_type	handler_signal;
	};

}

#include <needs_more_ninja/template/log/logger.inl>

#endif	//NMN_TEMPLATE_LOGGER_HPP
